import logging
from datetime import datetime
from multiprocessing import Process

import httpx
from fastmcp import FastMCP

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)

# -----------------------------
# Customer MCP Server
# -----------------------------
customer_mcp = FastMCP("customer-mcp-mcp")

# -----------------------------
# Account MCP Server
# -----------------------------
account_mcp = FastMCP("cbs-account-mcp")

# -----------------------------
# Transaction MCP Server
# -----------------------------
transaction_mcp = FastMCP("cbs-transaction-mcp")

# -----------------------------
# Payment MCP Server
# -----------------------------
payment_mcp = FastMCP("cbs-payment-mcp")

# 配置 API 地址
EXISTING_API_BASE_URL = "http://onebank-galaxygateway.dcits.sg"

http_client = httpx.AsyncClient(timeout=30)


async def call_existing_api(endpoint: str, method: str = "GET", data: dict | None = None):
    """Call existing RESTful API"""
    url = f"{EXISTING_API_BASE_URL}/{endpoint.lstrip('/')}"
    try:
        if method.upper() == "GET":
            response = await http_client.get(url)
        elif method.upper() == "POST":
            response = await http_client.post(url, json=data)
        elif method.upper() == "PUT":
            response = await http_client.put(url, json=data)
        elif method.upper() == "DELETE":
            response = await http_client.delete(url)
        else:
            raise Exception(f"Unsupported HTTP method: {method}")
        response.raise_for_status()
        resp = response.json()
        if resp and "sysHead" in resp and "ret" in resp["sysHead"]:
            ret_info = resp["sysHead"]["ret"][0] if resp["sysHead"]["ret"] else {}
            if ret_info.get("retCode") == "000000":
                return resp.get("body", {})
            else:
                raise Exception(f"API call failed: {ret_info.get('retMsg', '')}")
        else:
            raise Exception(f"Unexpected response format: {resp}")
    except httpx.RequestError as e:
        raise Exception(f"Request failed: {str(e)}")
    except httpx.HTTPStatusError as e:
        raise Exception(f"HTTP {e.response.status_code}: {e.response.text}")
    except Exception as e:
        raise Exception(f"{str(e)}")


@customer_mcp.tool(
    name="query_deposit_customer",
    description="Query deposit customer information by client number",
)
async def query_deposit_customer(client_no: str):
    logging.info("Query deposit account by client number: %s", client_no)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("rb/inq/acct/by/client", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "0008",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "clientNo": client_no
        }
    })


@customer_mcp.tool(
    name="query_loan_customer",
    description="Query loan customer information by client number",
)
async def query_loan_customer(client_no: str):
    logging.info("Query loan account by client number: %s", client_no)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("cl/inq/loan/multiInfo", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "2102",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "clientNo": client_no
        }
    })


@account_mcp.tool(
    name="query_deposit_account",
    description="Query deposit account information by account number",
)
async def query_deposit_account(account_no: str):
    logging.info("Query deposit account by account number: %s", account_no)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("rb/inq/channel/acct/info", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "0008",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "baseAcctNo": account_no
        }
    })


@account_mcp.tool(
    name="query_loan_account",
    description="Query loan account information by loan number"
)
async def query_loan_account(loan_no: str):
    logging.info("Query loan account by loan number: %s", loan_no)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("cl/inq/loan/info", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "2102",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "loanNo": loan_no
        }
    })


@transaction_mcp.tool(
    name="query_deposit_transaction_history",
    description="Query deposit transaction history"
)
async def query_deposit_transaction_history(
        account_no: str,
        start_date: str,
        end_date: str):
    logging.info("Query deposit transaction history by account number: %s, start date: %s, end date: %s", account_no,
                 start_date, end_date)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("rb/inq/tran/hist", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "0010",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "histKind": "1",
            "tranKind": "A",
            "baseAcctNo": account_no,
            "startDate": start_date,
            "endDate": end_date
        }
    })


@transaction_mcp.tool(
    name="query_loan_transaction_history",
    description="Query loan transaction history"
)
async def query_loan_transaction_history(loan_no: str,  # 贷款账号
                                         cmis_loan_no: str,  # 借据号
                                         start_date: str,
                                         end_date: str):
    logging.info(
        "Query loan transaction history by loan number: %s, cmis loan number: %s, start date: %s, end date: %s",
        loan_no, cmis_loan_no, start_date, end_date)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("cl/inq/loan/repay/query", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20240112",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "2102",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1400",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "loanNo": loan_no,
            "cmisloanNo": cmis_loan_no,
            "startDate": start_date,
            "endDate": end_date
        }
    })


@payment_mcp.tool(
    name="easy_deposit_repayment",
    description="Easy Loan repayment"
)
async def easy_loan_repayment(
        client_no: str,  # 客户号
        loan_no: str,  # 贷款账号
        cmis_loan_no: str,  # 借据号
        receipt_amt: int,  # 还款金额
        settle_base_acct_no: str  # 还款账户
):
    logging.info(
        "Easy Loan repayment by client number: %s, loan number: %s, cmis loan number: %s, receipt amount: %s, settle base account number: %s",
        client_no, loan_no, cmis_loan_no, receipt_amt, settle_base_acct_no)
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
    return await call_existing_api("cl/fin/loan/repayment", "POST", {
        "sysHead": {
            "authUserId": "",
            "tranDate": "20270304",
            "seqNo": timestamp,
            "tranMode": "ONLINE",
            "sourceBranchNo": "0101",
            "messageCode": "2302",
            "apprUserId": "",
            "programId": "3202",
            "destBranchNo": "0101",
            "branchId": "351002",
            "userId": "CS015",
            "apprFlag": "",
            "sourceType": "MT",
            "userLang": "CHINESE",
            "authFlag": "M",
            "tranTimestamp": timestamp,
            "messageType": "1000",
            "serviceCode": "MbsdCore",
            "sceneId": "01",
            "subSeqNo": timestamp
        },
        "appHead": {
            "totalNum": "-1",
            "pgupOrPgdn": "0",
            "totalFlag": "E",
            "pageStart": "0",
            "pageEnd": "0",
            "currentNum": "0"
        },
        "localHead": {},
        "body": {
            "clientNo": client_no,
            "loanNo": loan_no,
            "cmisloanNo": cmis_loan_no,
            "receiptAmt": receipt_amt,
            "settleBaseAcctNo": settle_base_acct_no,
            "prePaidFlag": "Y"
        }
    })


def run_customer_server():
    """Starts the customer MCP server."""
    customer_mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)


def run_account_server():
    """Starts the account MCP server."""
    account_mcp.run(transport="streamable-http", host="0.0.0.0", port=8001)


def run_transaction_server():
    """Starts the transaction MCP server."""
    transaction_mcp.run(transport="streamable-http", host="0.0.0.0", port=8002)


def run_payment_server():
    """Starts the payment MCP server."""
    payment_mcp.run(transport="streamable-http", host="0.0.0.0", port=8003)


# -----------------------------
# 启动入口
# -----------------------------
if __name__ == "__main__":
    p0 = Process(target=run_customer_server)
    p1 = Process(target=run_account_server)
    p2 = Process(target=run_transaction_server)
    p3 = Process(target=run_payment_server)

    print("Starting account, transaction, and payment servers...")

    # 启动进程
    p0.start()
    p1.start()
    p2.start()
    p3.start()

    # 保持主进程运行，直到所有子进程结束
    p0.join()
    p1.join()
    p2.join()
    p3.join()
